/*
 * Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.corba.se.impl.protocol;

import org.omg.CORBA.SystemException;
import org.omg.CORBA.OBJ_ADAPTER;
import org.omg.CORBA.UNKNOWN;
import org.omg.CORBA.CompletionStatus;

import org.omg.CORBA.portable.ServantObject;

import com.sun.corba.se.pept.protocol.ClientRequestDispatcher;

import com.sun.corba.se.spi.protocol.LocalClientRequestDispatcher;
import com.sun.corba.se.spi.protocol.LocalClientRequestDispatcherFactory;
import com.sun.corba.se.spi.protocol.ForwardException;

import com.sun.corba.se.spi.oa.ObjectAdapter;
import com.sun.corba.se.spi.oa.OAInvocationInfo;
import com.sun.corba.se.spi.oa.OADestroyed;

import com.sun.corba.se.spi.orb.ORB;

import com.sun.corba.se.spi.ior.IOR;

import com.sun.corba.se.spi.logging.CORBALogDomains;

import com.sun.corba.se.impl.logging.POASystemException;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;

public class POALocalCRDImpl extends LocalClientRequestDispatcherBase {
    private ORBUtilSystemException wrapper;
    private POASystemException poaWrapper;

    public POALocalCRDImpl(ORB orb, int scid, IOR ior) {
        super((com.sun.corba.se.spi.orb.ORB) orb, scid, ior);
        wrapper = ORBUtilSystemException.get(orb, CORBALogDomains.RPC_PROTOCOL);
        poaWrapper = POASystemException.get(orb, CORBALogDomains.RPC_PROTOCOL);
    }

    private OAInvocationInfo servantEnter(ObjectAdapter oa) throws OADestroyed {
        oa.enter();

        OAInvocationInfo info = oa.makeInvocationInfo(objectId);
        orb.pushInvocationInfo(info);

        return info;
    }

    private void servantExit(ObjectAdapter oa) {
        try {
            oa.returnServant();
        } finally {
            oa.exit();
            orb.popInvocationInfo();
        }
    }

    // Look up the servant for this request and return it in a
    // ServantObject.  Note that servant_postinvoke is always called
    // by the stub UNLESS this method returns null.  However, in all
    // cases we must be sure that ObjectAdapter.getServant and
    // ObjectAdapter.returnServant calls are paired, as required for
    // Portable Interceptors and Servant Locators in the POA.
    // Thus, this method must call returnServant if it returns null.
    public ServantObject servant_preinvoke(org.omg.CORBA.Object self, String operation, Class expectedType) {
        ObjectAdapter oa = oaf.find(oaid);
        OAInvocationInfo info = null;

        try {
            info = servantEnter(oa);
            info.setOperation(operation);
        } catch (OADestroyed ex) {
            // Destroyed POAs can be recreated by normal adapter activation.
            // So just reinvoke this method.
            return servant_preinvoke(self, operation, expectedType);
        }

        try {
            try {
                oa.getInvocationServant(info);
                if (!checkForCompatibleServant(info, expectedType))
                    return null;
            } catch (Throwable thr) {
                // Cleanup after this call, then throw to allow
                // outer try to handle the exception appropriately.
                servantExit(oa);
                throw thr;
            }
        } catch (ForwardException ex) {
            /* REVISIT
            ClientRequestDispatcher csub = (ClientRequestDispatcher)
                StubAdapter.getDelegate( ex.forward_reference ) ;
            IOR ior = csub.getIOR() ;
            setLocatedIOR( ior ) ;
            */
            RuntimeException runexc = new RuntimeException("deal with this.");
            runexc.initCause(ex);
            throw runexc;
        } catch (ThreadDeath ex) {
            // ThreadDeath on the server side should not cause a client
            // side thread death in the local case.  We want to preserve
            // this behavior for location transparency, so that a ThreadDeath
            // has the same affect in either the local or remote case.
            // The non-colocated case is handled in iiop.ORB.process, which
            // throws the same exception.
            throw wrapper.runtimeexception(ex);
        } catch (Throwable t) {
            if (t instanceof SystemException)
                throw (SystemException) t;

            throw poaWrapper.localServantLookup(t);
        }

        if (!checkForCompatibleServant(info, expectedType)) {
            servantExit(oa);
            return null;
        }

        return info;
    }

    public void servant_postinvoke(org.omg.CORBA.Object self, ServantObject servantobj) {
        ObjectAdapter oa = orb.peekInvocationInfo().oa();
        servantExit(oa);
    }
}

// End of file.
